#include <iostream>
#include <unistd.h>
#include <cassert>
#include <vector>
#include <string>
#include <sys/types.h>
#include <sys/wait.h>

#include "Task.hpp"

const static int num = 5;
static int number = 1;

// 信道的定义
class channel
{
public:
    channel(int fd, pid_t id)
        : ctrlfd(fd), workid(id)
    {
        name = "channel-" + std::to_string(number++);
    }

public:
    int ctrlfd;
    pid_t workid;
    std::string name;
};

void Work()
{
    while (true)
    {
        int code = 0;
        ssize_t n = read(0, &code, sizeof(code));
        if (n == sizeof(code))
        {
            // 读成功
            if (!init.CheckSafe(code))
                continue;
            init.RunTask(code);
        }
        else if (n == 0)
        {
            // 失败
            break;
        }
        else
        {
            // Do Nothing
        }
    }
}

void Printfd(const std::vector<int> &fds)
{
    std::cout << getpid() << " close fds: ";
    for (auto fd : fds)
    {
        std::cout << fd << " ";
    }
    std::cout << std::endl;
}

void CreateChannels(std::vector<channel> *c)
{
    std::vector<int> temp;
    for (int i = 0; i < num; i++)
    {
        // 1.定义并创建管道
        int pipefd[2] = {0};
        int n = pipe(pipefd);
        assert(n == 0);
        (void)n;

        // 2.创建进程
        pid_t id = fork();
        assert(id != -1);

        // 3.构建单向通信信道
        if (id == 0) // child
        {
            if (!temp.empty())
            {
                for (auto fd : temp)
                {
                    close(fd);
                }
                Printfd(temp);
            }
            close(pipefd[1]);
            dup2(pipefd[0], 0); // 将标准输入指定为从pipefd[0]中读取
            Work();
            exit(0);
        }

        // father
        close(pipefd[0]);
        c->push_back(channel(pipefd[1], id));
        temp.push_back(pipefd[1]);
    }
}

void SendCommand(const std::vector<channel> &channels, bool flag, int num = -1)
{
    int pos = 0;

    while (true)
    {
        // 1. 选择任务
        int command = init.SelectTask();

        // 2. 选择信道
        auto &channel = channels[pos++];
        pos %= channels.size();

        // debug
        std::cout << "send command " << init.ToDesc(command) << "[" << command << "]"
                  << " in "
                  << channel.name << " worker is : " << channel.workid << std::endl;

        // 3. 发送任务
        write(channel.ctrlfd, &command, sizeof(command));

        // 4. 判断是否要退出
        if (!flag)
        {
            num--;
            if (num <= 0)
                break;
        }
        sleep(1);
    }
    std::cout << "SendCommand done..." << std::endl;
}

void ReleaseChannel(const std::vector<channel> &c)
{
    for (auto &channels : c)
    {
        close(channels.ctrlfd);
        pid_t rid = waitpid(channels.workid, nullptr, 0);
        if (rid == channels.workid)
        {
            std::cout << "wait child: " << channels.workid << " success" << std::endl;
        }
    }
    // for (const auto &channel : c)
    // {
    //     pid_t rid = waitpid(channel.workid, nullptr, 0);
    //     if (rid == channel.workid)
    //     {
    //         std::cout << "wait child: " << channel.workid << " success" << std::endl;
    //     }
    // }
}

int main()
{

    // while :; do ps ajx | head -1 && ps ajx | grep   processpool; sleep 1; done

    std::vector<channel> channels;

    // 1. 创建信道，创建进程
    CreateChannels(&channels);

    // 2. 开始发送任务
    const bool g_always_loop = true;
    // SendCommand(channels, g_always_loop);
    SendCommand(channels, !g_always_loop, 10);

    // 3. 回收资源，想让子进程退出，并且释放管道，只要关闭写端
    ReleaseChannel(channels);
    return 0;
}
